package com.cqie.rbac.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cqie.rbac.mapper.SysMenuMapper;
import com.cqie.rbac.service.ISysMenuService;
import com.cqie.rbac.bo.MenuBo;
import com.cqie.rbac.entity.SysMenu;
import com.cqie.rbac.exception.BusinessException;
import com.cqie.rbac.mapper.SysRoleMapper;
import com.cqie.rbac.util.JwtUtils;
import com.cqie.rbac.util.NavNode;
import com.cqie.rbac.util.Result;
import com.cqie.rbac.util.TreeNode;
import com.cqie.rbac.vo.MenuVo;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * <p>
 * 菜单实体 服务实现类
 * </p>
 *
 * @author 夏兵
 * @since 2021-09-02
 */
@Service
@Log4j
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Override
    public Result menuTree() {
        LambdaQueryWrapper<SysMenu> rootWrapper = new LambdaQueryWrapper<>();
        rootWrapper.eq(SysMenu::getParentId, 0);
        rootWrapper.orderByAsc(SysMenu::getSortCode);
        List<SysMenu> firstMenu = baseMapper.selectList(rootWrapper);
        List<TreeNode> result = new ArrayList<>(firstMenu.size());
        for (SysMenu menu : firstMenu) {
            TreeNode treeNode = new TreeNode();
            treeNode.setId(menu.getId());
            treeNode.setName(menu.getName());
            treeNode.setAppUrl(menu.getAppUrl());
            treeNode.setImgUrl(menu.getImgUrl());
            treeNode.setPermissionCode(menu.getPermissionCode());
            treeNode.setMenuType(menu.getMenuType());
            treeNode.setParentId(menu.getParentId());
            treeNode.setCreateTime(menu.getCreateTime());
            result.add(treeNode);
        }
        for (TreeNode node : result) {
            node.setChildren(this.getChildren(node.getId()));
        }
        return Result.ok().data(result);
    }

    @Override
    public Result getRoleMenu(Long id) {
        if (id == null) {
            log.error("传入id为空");
            throw new BusinessException("5000", "查询失败");
        }
        return Result.ok().data(sysMenuMapper.getRoleMenu(id));
    }

    @Override
    public Result delMenu(Long delId) {
        if (sysMenuMapper.delMenuAndSon(delId) < 1) {
            log.error("删除菜单出错");
            throw new BusinessException("5000", "删除菜单失败");
        }
        return Result.ok();
    }

    @Override
    public Result getMenuById(Long id) {
        SysMenu menu = new SysMenu();
        menu.setId(id);
        SysMenu temp = baseMapper.selectById(menu);
        return Result.ok().data(new MenuVo(temp.getId(), temp.getName(), temp.getAppUrl(),
                temp.getImgUrl(), temp.getPermissionCode(), temp.getParentId()));
    }

    @Override
    public Result updateOrAddMenu(MenuBo menuBo) {
        SysMenu menu = new SysMenu();
        menu.setName(menuBo.getName());
        LambdaQueryWrapper<SysMenu> queryNameWrapper = new LambdaQueryWrapper<>();
        queryNameWrapper.eq(SysMenu::getName, menuBo.getName());
        if (menuBo.getTag() > 0 || !menuBo.getOriginName().equals(menuBo.getName())) {
            if (baseMapper.selectOne(queryNameWrapper) != null) {
                log.error("该菜单名已存在，新增失败");
                throw new BusinessException("5000", "该菜单名已存在");
            }
        }
        if (menuBo.getTag() > 0) {
            LambdaQueryWrapper<SysMenu> queryCodeWrapper = new LambdaQueryWrapper<>();
            queryCodeWrapper.eq(SysMenu::getPermissionCode, menuBo.getPermissionCode());
            if (baseMapper.selectOne(queryCodeWrapper) != null) {
                log.error("该权限码已存在，新增失败");
                throw new BusinessException("5000", "该权限码已存在");
            }
        }
        menu.setAppUrl(menuBo.getAppUrl());
        menu.setImgUrl(menuBo.getImgUrl());
        if (menuBo.getTag() > 0) {
            menu.setParentId(menuBo.getParentId());
            menu.setPermissionCode(menuBo.getPermissionCode());
            if (menuBo.getTag() > 1) {
                Integer sort = baseMapper.sonMenuMaxCode(0L);
                menu.setPermissionCode(menuBo.getPermissionCode());
                if (sort == null) {
                    menu.setSortCode(1);
                } else {
                    menu.setSortCode(sort + 1);
                }
            } else {
                Integer sort = baseMapper.sonMenuMaxCode(menuBo.getParentId());
                if (sort == null) {
                    menu.setSortCode(1);
                } else {
                    menu.setSortCode(sort + 1);
                }
            }
            baseMapper.insert(menu);
        } else {
            menu.setId(menuBo.getId());
            baseMapper.updateById(menu);
        }
        return Result.ok();
    }

    @Override
    public Result getNavMenu() {
        String id = JwtUtils.getMemberIdByJwtToken(request);
        List<SysMenu> childMenu = baseMapper.queryUserMenu(Long.parseLong(id));
        Set<Long> parentIdSet = new HashSet<>();
        for (SysMenu menu : childMenu) {
            parentIdSet.add(menu.getParentId());
        }
        Set<SysMenu> res = new HashSet<>();
        getNavChildren(res, parentIdSet);
        List<SysMenu> firstMenu = new ArrayList<>();
        Iterator<SysMenu> iterator = res.iterator();
        // 获取一级菜单
        while (iterator.hasNext()) {
            SysMenu menu = iterator.next();
            if (menu.getParentId() == 0) {
                firstMenu.add(menu);
                iterator.remove();
            }
        }

        List<NavNode> navNodes = new ArrayList<>();
        for (SysMenu first : firstMenu) {
            NavNode navNode = new NavNode(first.getId(), first.getName(), first.getAppUrl(), first.getImgUrl());
            navNode.setChildren(setChild(first, res));
            navNodes.add(navNode);
        }
        return Result.ok().data(navNodes);
    }

    public List<TreeNode> getChildren(Long fatherId) {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getParentId, fatherId);
        queryWrapper.orderByAsc(SysMenu::getSortCode);
        List<SysMenu> childrenMenu = baseMapper.selectList(queryWrapper);
        if (childrenMenu.size() < 1) {
            return null;
        }
        List<TreeNode> treeNodes = new ArrayList<>(childrenMenu.size());
        for (SysMenu menu : childrenMenu) {
            TreeNode treeNode = new TreeNode();
            treeNode.setId(menu.getId());
            treeNode.setName(menu.getName());
            treeNode.setAppUrl(menu.getAppUrl());
            treeNode.setImgUrl(menu.getImgUrl());
            treeNode.setPermissionCode(menu.getPermissionCode());
            treeNode.setMenuType(menu.getMenuType());
            treeNode.setParentId(menu.getParentId());
            treeNode.setCreateTime(menu.getCreateTime());
            treeNodes.add(treeNode);
        }
        for (TreeNode node : treeNodes) {
            if (node.getId() != null) {
                node.setChildren(getChildren(node.getId()));
            }
        }
        return treeNodes;
    }

    public void getNavChildren(Set<SysMenu> res, Set<Long> parentId) {
        if (parentId.size() < 1) {
            return;
        }
        Set<Long> parentIdSet = new HashSet<>();
        for (Long parent : parentId) {
            LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysMenu::getId, parent);
            SysMenu menu = baseMapper.selectOne(queryWrapper);
            if (menu != null) {
                res.add(menu);
                parentIdSet.add(menu.getParentId());
            }
        }
        getNavChildren(res, parentIdSet);
    }

    public List<NavNode> setChild(SysMenu father, Set<SysMenu> res) {
        List<NavNode> nodes = null;
        Iterator<SysMenu> iterator = res.iterator();
        while (iterator.hasNext()) {
            SysMenu menu = iterator.next();
            if (father.getId().equals(menu.getParentId())) {
                if (nodes == null) {
                    nodes = new ArrayList<>();
                }
                NavNode child = new NavNode(menu.getId(), menu.getName(), menu.getAppUrl(), menu.getImgUrl());
                child.setChildren(setChild(menu, res));
                nodes.add(child);
            }
        }
        return nodes;
    }
}
